package com.study.java.classloader.myClassLoader.NetClassLoader;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;

/**
* @Name: NetClassLoader
* @Description: 自定义网路类加载器
* 功能：加载指定目录的Class字节码文件
* @Author: 李超	lc_jack@foxmail.com
* @CreateDate: 2017-2-9 下午3:05:38 
* @Version: V1.0
 */
public class NetClassLoader extends ClassLoader {
	
	//指定网络URL路径
	private String rootUrl ;

	public NetClassLoader(String rootUrl) {
		this.rootUrl = rootUrl ;
	}
	
	/**
	* @Name: findClass
	* @Description: 重写父类的类加载方法
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-2-9 下午2:43:47
	* @Parameters: String name 字节码文件的全路径：包.类
	* @Return: Class<?> 被加载的字节码文件对象
	 */
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		//检查请求的类型是否已经被这个类加载器所加载
		Class<?> clazz = findLoadedClass(name) ;
		//如果已经加载，直接返回已加载的字节码文件对象
		if(clazz != null) {
			return clazz ;
		} else { //如果没有被加载，使用双亲委派机制加载该字节码文件
			//获取父类加载器
			ClassLoader parentClassLoader = getParent() ;
			//首先委派给父类加载
			try {
				clazz = parentClassLoader.loadClass(name) ;
			} catch (ClassNotFoundException e) {
				System.out.println("父类无法加载该字节码文件！");
			}
			if(clazz != null) {
				return clazz ;
			} else { //如果父类无法加载该字节码文件，则由自己进行加载
				byte[] classData = getClassData(name) ;
				if(classData == null) {
					throw new ClassNotFoundException() ;
				} else {
					clazz = defineClass(name, classData, 0, classData.length) ;
				}
			}
		}
		return clazz ;
	}

	/**
	* @Name: getClassData
	* @Description: 读取指定网络路径下的字节码文件，将其转换成字节数组
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-2-9 下午3:38:35
	* @Parameters: @param classname 字节码文件的全路径：包.类
	* @Parameters: @return
	* @Return: byte[]
	 */
	private byte[] getClassData(String classname) {
		//拼接字节码文件路径
		String classPath = rootUrl + "/" + classname.replace(".", "/") + ".class" ;
		//可以使用IOUtils将流数据转换成字节数组
		InputStream is = null ;
		ByteArrayOutputStream baos = null ;
		try {
			URL url = new URL(classPath) ;
			is = url.openStream() ;
			baos = new ByteArrayOutputStream() ;
			byte[] buf = new byte[1024] ;
			int len = 0 ;
			while((len = is.read(buf)) != -1) {
				baos.write(buf, 0, len) ;
			}
			return baos.toByteArray() ;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			if(is != null) {
				try {
					is.close() ;
				} catch (Exception e2) {
					e2.printStackTrace() ;
				} finally {
					is = null ;
				}
			}
			if(baos != null) {
				try {
					baos.close() ;
				} catch (Exception e2) {
					e2.printStackTrace() ;
				} finally {
					baos = null ;
				}
			}
		}
	}

}
